package com.xuxk.project.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.xuxk.project.gateway.util.JwtUtil;
import com.xuxk.project.util.DESUtil;
import com.xuxk.project.util.ErrResponseBody;
import com.xuxk.project.util.JwtBaseInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Set;

/**
 * 鉴权过滤器
 */
@Component
@RefreshScope
public class AuthFilter implements GlobalFilter, Ordered {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthFilter.class);

    @Value("${auth.skip.urls}")
    private String[] skipAuthUrls;
    @Value("${auth.secret.key}")
    private String secretKey;

    @Value("${spring.application.name}")
    private String applicationName;

    private static String ONLINE_USERID_KEY="online:ec:userAccount:%s";



    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String url = exchange.getRequest().getURI().getPath();
        String method=exchange.getRequest().getMethod().toString();
        PathMatcher matcher = new AntPathMatcher();
        //跳过不需要验证的路径
        if (skipAuthUrls != null){
            for (String skipUrl :skipAuthUrls) {
                if (matcher.match(skipUrl,url)){
                    return chain.filter(exchange);
                }
            }
        }

        //从请求头中取出token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");

        if(StringUtils.isEmpty(token))
        {
            ServerHttpResponse originalResponse = exchange.getResponse();
            ErrResponseBody responseBody=new ErrResponseBody();
            responseBody.setCode(20001);
            responseBody.setMsg("非法请求");
            return returnRes(originalResponse,responseBody);
        }
        DecodedJWT decodedJWT=jwtUtil.verifyJWT(token,secretKey);
        JwtBaseInfo info = null;
        try {
            info= JSON.parseObject(DESUtil.Decryptor(decodedJWT.getClaim(JwtBaseInfo.INFO).asString(),secretKey),JwtBaseInfo.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(decodedJWT==null || info==null)
        {
            ServerHttpResponse originalResponse = exchange.getResponse();
            ErrResponseBody responseBody=new ErrResponseBody();
            responseBody.setCode(20002);
            responseBody.setMsg("token失效");
            return returnRes(originalResponse,responseBody);
        }
        //TODO 从Redis获取当前用户信息用于鉴权
        //1.获取当前登录uuid和user判断是否失效
        String uuid=stringRedisTemplate.opsForValue().get(String.format(ONLINE_USERID_KEY,info.getLoginAccout()));
        if(uuid.isEmpty() || (!uuid.equals(info.getUuid())))
        {
            ServerHttpResponse originalResponse = exchange.getResponse();
            ErrResponseBody responseBody=new ErrResponseBody();
            responseBody.setCode(20003);
            responseBody.setMsg("token过期");
            return returnRes(originalResponse,responseBody);
        }
        //将现在的request，添加当前身份
        ServerHttpRequest mutableReq = exchange.getRequest().mutate().header("Authorization-Info", JSON.toJSONString(info)).build();
        ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
        return chain.filter(mutableExchange);
    }

    @Override
    public int getOrder() {
        return -200;
    }

    private Mono<Void> returnRes(ServerHttpResponse originalResponse,ErrResponseBody responseBody)
    {
        originalResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
        originalResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        responseBody.setSys(applicationName);
        byte[] response = JSONObject.toJSONString(responseBody).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = originalResponse.bufferFactory().wrap(response);
        return originalResponse.writeWith(Flux.just(buffer));
    }
}
